package ipc;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import rddl.RDDL;
import rddl.RDDL.DOMAIN;
import rddl.RDDL.INSTANCE;
import rddl.RDDL.NONFLUENTS;

import java.io.File;

import rddl.parser.parser;

public class SPUDDer extends Thread{

	public static ConcurrentHashMap<String, SPUDD> threads = new ConcurrentHashMap<String, SPUDD>();
	List<String> instances;
	public int current = 0;
	RDDL rddlset;
	long timeout;
	public static boolean running = false;	
	public int loaded = 0;

	public SPUDDer(List<String> instances, String dirname, long timeout ) {
		rddlset = new RDDL();
		File f = new File(dirname);
		if (f.isDirectory()) {
			for (File f2 : f.listFiles())
				if (!f2.getName().contains("pomdp")) {
	try {
						rddlset.addOtherRDDL(parser.parse(f2));
					} catch (Exception e) {
						Main.exceptionLog.log("exception in parsing rddl file\n"+e.getMessage());
					}
				}
		} else
			try {
				rddlset.addOtherRDDL(parser.parse(f));
			} catch (Exception e) {
				Main.exceptionLog.log("exception in parsing rddl file\n"+e.getMessage());
			}

		f = new File(dirname+"/traffic_mdp.rddl.translate");

		try{
			rddlset.addOtherRDDL(parser.parse(f)); 
		}catch(Exception e){
			e.printStackTrace();
		}

		this.rddlset = rddlset;

		running = false;
		this.instances = instances;
		this.current = 0;
		this.timeout = timeout;
		this.setPriority(Thread.MAX_PRIORITY-2);
		loadNext();
//		try{
//
//			startNext().join();
//		}catch(Exception e){
//		}
		
	}

	public void loadNext(){
		if( loaded == instances.size() )
			return;
		String inst = instances.get(loaded);
		++loaded;
	
		INSTANCE _i = rddlset._tmInstanceNodes.get(inst);
		_i._nNonDefActions = 1;
		DOMAIN _d = rddlset._tmDomainNodes.get(_i._sDomain);
		NONFLUENTS _n = rddlset._tmNonFluentNodes.get(_i._sNonFluents);

		if( _i == null || _d == null || _n == null)
			throw new RuntimeException("could not load rddl");


		RDDL solving = new RDDL();
		solving.addDomain(_d);
		solving.addInstance(_i);
		solving.addNonFluents(_n);

//			int ndef = _i._nNonDefActions;
//			_i._nNonDefActions = 1;

		try{
			RDDL2SPUDD r2s = new RDDL2SPUDD(solving, inst, RDDL2SPUDD.SPUDD_CURR, 1);
		}catch(Exception e){
			e.printStackTrace();
		}		
//			_i._nNonDefActions = ndef;
	}	

	public void run() {

		while( current != instances.size() ){
			if( running ){ 
			
				boolean thru = true;
		//		System.err.println(threads.size());
				for( SPUDD sp : threads.values() ){
					if( sp.running ){
						thru  = false;
						break;
					}
				}	
				if( !thru ){
					 loadNext();
					 continue;
				}else
					running = false;
			}
			System.err.println("no spudd");
			if( loaded > current ) {
				startNext();
			}else{
				loadNext();
				startNext();
			}
		}	
			
		//	try {
		//		spudd.join();		
		//	} catch (InterruptedException e) {
		//		Main.exceptionLog.log("SPUDD interrupted " + inst );
	}

	public SPUDD startNext(){
			String inst = instances.get(current);
			++current;
//			Main.activityLog.log("Number of objects " + _i._hmObjects.size());
		        System.out.println("Starting " + inst);	
			Main.spuddLog.log("Starting " + inst);	

			//FIXME: 40 hard coded 
 
			SPUDD spudd = new SPUDD(inst+".spudd", 0, 40);
			spudd.start();
			threads.put(inst, spudd);
			running = true;
			try{
				this.sleep(5000);
			}catch(Exception e){
				
			}


			return spudd;
	}

	public static boolean isFinished(String instance_name, int hor) {
		SPUDD spudd = threads.get(instance_name);
		if( spudd == null ){
//			Main.exceptionLog.log("spudd thread null which checking isfinished " + instance_name);
			return false;
			
		}
		return spudd.isFinished(hor);
	}
	
	public static void updateDD(String instance_name, long timeout){
		SPUDD spudd = threads.get(instance_name);
		if( spudd == null ){
//			Main.exceptionLog.log("SPUDD thread null while updating DD!!! "+instance_name);
//			Main.spuddLog.log("SPUDD thread null while updating DD!!! "+instance_name);
			return;
		}
		spudd.updateDD(timeout);
		return;
	}
	
	public static myDD getDD(String instance_name, boolean value, int hor){
		SPUDD spudd = threads.get(instance_name);
		if( spudd == null ){
//			Main.exceptionLog.log("SPUDD thread null while getting DD!!! "+instance_name+" "+value);
//			Main.spuddLog.log("SPUDD thread null while getting DD!!! "+instance_name+" "+value);
			return null;
		}
		return spudd.getDD(value, hor);
	}

	public static void kill(String inst) {
		System.out.println("SPUDDer Killing " + inst);
		Main.spuddLog.log("SPUDDer Killing " + inst);


		SPUDD spudd = threads.get(inst);
		if( spudd == null ){
//			Main.exceptionLog.log("SPDUD thread null while killing " + inst);
			return;
		}
		spudd.kill();
	}
	
	public static double getRange(String inst, int hor){
		SPUDD spudd = threads.get(inst);
		if( spudd == null ){
//			Main.exceptionLog.log("SPUDD thread null while getRange " + inst);
			return 0;
		}
		return spudd.getRange(hor);
	}
	
	public static void updateRange(String inst){
		SPUDD spudd = threads.get(inst);
		if( spudd == null ){
//			Main.exceptionLog.log("SPUDD thread null while getRange " + inst);
			return;
		}
		spudd.updateRange();
	}

	public static void done(String inst){
		SPUDD spudd = threads.get(inst);
		if( spudd == null ){
//			Main.exceptionLog.log("SPUDD thread null while getRange " + inst);
			return;
		}
		spudd.done();
	}

	public static int getLastSeen(String inst_name) {
		SPUDD spudd = threads.get(inst_name);
		if( spudd != null ){
			return spudd.getLastSeen();
		}
		return -1;
	}
}
